/*
 * Copyright 2017 hv0912
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.vimhe.ezimp2.handler.reader;

import com.vimhe.ezimp2.config.ImportConfig;
import com.vimhe.ezimp2.config.bean.RowConfig;
import com.vimhe.ezimp2.handler.Reader;
import com.vimhe.ezimp2.handler.bean.CellData;
import com.vimhe.ezimp2.util.ExcelColumnIndexUtils;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
import org.apache.poi.hssf.record.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Excel2003表格解析处理驱动
 *
 * @author Vimhe
 */
public final class Excel2003Handler implements HSSFListener {

    /**
     * 数据读取器
     */
    private Reader reader;

    /**
     * 配置管理对象
     */
    private ImportConfig importConfig;

    /**
     * Records we pick up as we process
     */
    private SSTRecord sstRecord;
    private FormatTrackingHSSFListener formatListener;

    /**
     * 用于处理带有字符串结果的公式
     */
    private boolean outputNextStringRecord;

    /**
     * 文件索引
     */
    private String fileIndex;

    /**
     * 当前工作表
     */
    private int sheetIndex = 0;
    private BoundSheetRecord[] orderedBSRs;
    private List<BoundSheetRecord> boundSheetRecords = new ArrayList<>();

    /**
     * 行
     */
    private int rowIndex = -1;
    private int lastRowIndex;
    private int nextRowIndex;

    /**
     * 列
     */
    private int cellIndex = -1;
    private int lastCellIndex;
    private int nextCellIndex;

    private Map<String, Object> rowValue;
    private Map<Integer, Map<String, Object>> sheetValue;
    private Map<Integer, Map<Integer, Map<String, Object>>> fileValue = new HashMap<>(16);

    public Excel2003Handler(Reader reader, ImportConfig importConfig) {
        this.reader = reader;
        this.importConfig = importConfig;
    }

    @Override
    public void processRecord(Record record) {
        String thisStr = null;

        switch (record.getSid()) {
            case BoundSheetRecord.sid:
                boundSheetRecords.add((BoundSheetRecord) record);
                break;
            case BOFRecord.sid:
                BOFRecord br = (BOFRecord) record;
                if (br.getType() == BOFRecord.TYPE_WORKSHEET) {
                    sheetValue = new HashMap<>(128);
                    sheetIndex++;
                    if (orderedBSRs == null) {
                        orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
                    }
                }
                break;
            case SSTRecord.sid:
                sstRecord = (SSTRecord) record;
                break;
            case BlankRecord.sid:
                BlankRecord blankRecord = (BlankRecord) record;

                thisStr = "";
                rowIndex = blankRecord.getRow();
                cellIndex = blankRecord.getColumn();
                break;
            case BoolErrRecord.sid:
                BoolErrRecord boolErrRecord = (BoolErrRecord) record;

                thisStr = "";
                rowIndex = boolErrRecord.getRow();
                cellIndex = boolErrRecord.getColumn();
                break;
            case FormulaRecord.sid:
                FormulaRecord formulaRecord = (FormulaRecord) record;

                rowIndex = formulaRecord.getRow();
                cellIndex = formulaRecord.getColumn();

                if (Double.isNaN(formulaRecord.getValue())) {
                    // 公式结果是一个字符串
                    // 它存储在下一个记录
                    outputNextStringRecord = true;
                    nextRowIndex = formulaRecord.getRow();
                    nextCellIndex = formulaRecord.getColumn();
                } else {
                    thisStr = formatListener.formatNumberDateCell(formulaRecord);
                }
                break;
            case StringRecord.sid:
                if (outputNextStringRecord) {
                    // 公式的字符串
                    StringRecord stringRecord = (StringRecord) record;

                    thisStr = stringRecord.getString();
                    rowIndex = nextRowIndex;
                    cellIndex = nextCellIndex;
                    outputNextStringRecord = false;
                }
                break;

            case LabelRecord.sid:
                LabelRecord labelRecord = (LabelRecord) record;

                thisStr = labelRecord.getValue();
                rowIndex = labelRecord.getRow();
                cellIndex = labelRecord.getColumn();
                break;
            case LabelSSTRecord.sid:
                LabelSSTRecord labelSSTRecord = (LabelSSTRecord) record;

                if (sstRecord == null) {
                    thisStr = "";
                } else {
                    thisStr = sstRecord.getString(labelSSTRecord.getSSTIndex()).toString();
                }
                rowIndex = labelSSTRecord.getRow();
                cellIndex = labelSSTRecord.getColumn();
                break;
            case NoteRecord.sid:
                NoteRecord noteRecord = (NoteRecord) record;

                thisStr = '"' + "(TODO)" + '"';
                rowIndex = noteRecord.getRow();
                cellIndex = noteRecord.getColumn();
                break;
            case NumberRecord.sid:
                NumberRecord numberRecord = (NumberRecord) record;

                // 格式化
                thisStr = formatListener.formatNumberDateCell(numberRecord);
                rowIndex = numberRecord.getRow();
                cellIndex = numberRecord.getColumn();
                break;
            case RKRecord.sid:
                RKRecord rkRecord = (RKRecord) record;

                thisStr = '"' + "(TODO)" + '"';
                rowIndex = rkRecord.getRow();
                cellIndex = rkRecord.getColumn();
                break;
            case EOFRecord.sid:
                // 对工作表的数据进行处理
                //sheetValue = excelReader.readSheet(sheetIndex, sheetValue);

                if (sheetValue != null) {
                    fileValue.put(sheetIndex, sheetValue);
                }
                break;
            default:
                break;
        }

        // 处理新的行
        if (rowIndex != -1 && rowIndex != lastRowIndex) {
            lastCellIndex = -1;
        }

        // 处理缺少的列
        if (record instanceof MissingCellDummyRecord) {
            MissingCellDummyRecord missingCellDummyRecord = (MissingCellDummyRecord) record;
            thisStr = "";
            rowIndex = missingCellDummyRecord.getRow();
            cellIndex = missingCellDummyRecord.getColumn();
        }

        // 向rowValue中添加当前数据
        if (thisStr != null) {
            if (cellIndex == 0) {
                rowValue = new HashMap<>(16);
            }
            if (cellIndex > -1) {
                String colName = ExcelColumnIndexUtils.number2Index(cellIndex + 1);

                CellData cellData = new CellData(fileIndex, sheetIndex, rowIndex, colName);
                cellData.setValue("");
//                RxBus.getInstance().post(cellData);
//
//                // 对当前单元格的数据进行处理
//                thisStr = (String) excelReader.readCell(sheetIndex, rowIndex + 1, cellIndexA, thisStr);
//
//                if (thisStr != null) {
//                    rowValue.put(cellIndexA, thisStr);
//                }
            }
        }

        // 记录当前行索引
        if (rowIndex > -1) {
            lastRowIndex = rowIndex;
        }

        // 记录当前单元格索引
        if (cellIndex > -1) {
            lastCellIndex = cellIndex + 1;
        }

        // 处理行的结尾
        if (record instanceof LastCellOfRowDummyRecord) {
            // 处理行尾的空数据
            RowConfig rowConfig = importConfig.getRowConfig(fileIndex, sheetIndex, rowIndex + 1);
            if (rowConfig == null) {
                return;
            }
            int minColumns = rowConfig.getColumnConfigMap().size();
            if (minColumns > 0) {
                // 列是基于0的
                if (lastCellIndex == -1) {
                    lastCellIndex = 0;
                }
                for (int i = lastCellIndex; i < (minColumns); i++) {
                    // 对当前单元格的数据进行处理
                    String colName = ExcelColumnIndexUtils.number2Index(i + 1);

                    CellData cellData = new CellData(fileIndex, sheetIndex, rowIndex, colName);
                    cellData.setValue("");

//                    RxBus.getInstance().post(cellData);
                }
            }

            // 对当前行的数据进行处理
            //rowValue = excelReader.readRow(sheetIndex, rowIndex + 1, rowValue);
            if (rowValue != null) {
                sheetValue.put(rowIndex + 1, rowValue);
            }

            // 重置计数器
            lastCellIndex = -1;
        }
    }

    /**
     * 遍历工作表中所有的电子表格
     *
     * @param fileIndex   文件索引
     * @param inputStream 文件流
     * @throws IOException e
     */
    public void process(String fileIndex, InputStream inputStream) throws IOException {
        this.fileIndex = fileIndex;

        POIFSFileSystem poifsFileSystem = new POIFSFileSystem(inputStream);
        HSSFRequest request = new HSSFRequest();
        MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
        formatListener = new FormatTrackingHSSFListener(listener);
        request.addListenerForAllRecords(formatListener);
        HSSFEventFactory factory = new HSSFEventFactory();
        factory.processWorkbookEvents(request, poifsFileSystem);
        //excelReader.readFile(fileValue);
    }

}
